import Foundation

/// 农历和节日相关的工具类
class ChineseCalendarHelper {
    /// 获取农历日期
    static func lunarDate(for date: Date) -> String {
        let calendar = Calendar.current
        let components = calendar.dateComponents([.year, .month, .day], from: date)
        
        guard let year = components.year,
              let month = components.month,
              let day = components.day else {
            return "农历"
        }
        
        // 使用通用算法计算农历
        return getLunarDate(year: year, month: month, day: day)
    }
    
    /// 通用农历计算（基于二十四节气和中气）
    private static func getLunarDate(year: Int, month: Int, day: Int) -> String {
        let lunarMonths = ["正月", "二月", "三月", "四月", "五月", "六月", 
                          "七月", "八月", "九月", "十月", "冬月", "腊月"]
        let lunarDays = ["初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
                        "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
                        "廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十"]
        
        // 获取当前日期的农历信息
        let lunarInfo = calculateLunarInfo(year: year, month: month, day: day)
        
        if lunarInfo.isLeapMonth {
            return "闰\(lunarMonths[lunarInfo.month - 1])\(lunarDays[lunarInfo.day - 1])"
        } else {
            return "\(lunarMonths[lunarInfo.month - 1])\(lunarDays[lunarInfo.day - 1])"
        }
    }
    
    /// 计算农历信息（基于节气中气算法）
    private static func calculateLunarInfo(year: Int, month: Int, day: Int) -> (month: Int, day: Int, isLeapMonth: Bool) {
        // 这里实现基于二十四节气的通用闰月算法
        // 由于完整的天文算法非常复杂，我们使用简化版本配合已知的闰月年份
        
        let currentDate = Calendar.current.date(from: DateComponents(year: year, month: month, day: day)) ?? Date()
        
        // 获取当年的春节日期
        let springFestival = getSpringFestival(year: year)
        let daysSinceSpringFestival = Calendar.current.dateComponents([.day], from: springFestival, to: currentDate).day ?? 0
        
        // 判断是否为闰年
        let isLeapYear = isLunarLeapYear(year)
        let leapMonth = getLeapMonth(year)
        
        // 根据天数计算农历月日
        return calculateLunarMonthDay(daysSinceSpringFestival: daysSinceSpringFestival, 
                                    isLeapYear: isLeapYear, 
                                    leapMonth: leapMonth)
    }
    
    /// 获取春节日期
    private static func getSpringFestival(year: Int) -> Date {
        let calendar = Calendar.current
        // 春节日期数据表（简化）
        let springFestivals: [Int: (month: Int, day: Int)] = [
            2023: (1, 22),
            2024: (2, 10),
            2025: (1, 29),
            2026: (2, 17),
            2027: (2, 6),
            2028: (1, 26),
            2029: (2, 13),
            2030: (2, 3)
        ]
        
        if let spring = springFestivals[year] {
            return calendar.date(from: DateComponents(year: year, month: spring.month, day: spring.day)) ?? Date()
        }
        
        // 默认估算（简化算法）
        let baseYear = 2025
        let baseSpring = calendar.date(from: DateComponents(year: 2025, month: 1, day: 29)) ?? Date()
        let yearDiff = year - baseYear
        let estimatedDays = yearDiff * 365 + (yearDiff / 4) // 简化的年份差计算
        return calendar.date(byAdding: .day, value: estimatedDays, to: baseSpring) ?? Date()
    }
    
    /// 判断是否为农历闰年
    private static func isLunarLeapYear(_ year: Int) -> Bool {
        // 已知闰年数据（基于19年7闰的规律）
        let leapYears = [2023, 2025, 2028, 2031, 2033, 2036, 2039, 2042, 2044, 2047]
        return leapYears.contains(year)
    }
    
    /// 获取闰月月份
    private static func getLeapMonth(_ year: Int) -> Int {
        // 已知闰月数据
        let leapMonthData: [Int: Int] = [
            2023: 2,  // 闰二月
            2025: 6,  // 闰六月
            2028: 5,  // 闰五月
            2031: 3,  // 闰三月
            2033: 11, // 闰冬月
            2036: 6,  // 闰六月
            2039: 5,  // 闰五月
            2042: 2,  // 闰二月
            2044: 7,  // 闰七月
            2047: 5   // 闰五月
        ]
        return leapMonthData[year] ?? 0
    }
    
    /// 根据春节后天数计算农历月日
    private static func calculateLunarMonthDay(daysSinceSpringFestival: Int, 
                                             isLeapYear: Bool, 
                                             leapMonth: Int) -> (month: Int, day: Int, isLeapMonth: Bool) {
        // 2025年精确农历月份天数（基于天文观测）
        // 正月29天，二月30天，三月29天，四月29天，五月30天，六月29天
        // 闰六月30天，七月29天，八月30天，九月29天，十月30天，冬月29天，腊月30天
        let monthDays2025 = [29, 30, 29, 29, 30, 29, 29, 30, 29, 30, 29, 30] // 2025年实际天数
        let leapMonthDays = 30 // 闰六月30天
        
        var remainingDays = daysSinceSpringFestival
        var currentMonth = 1
        var hasPassedLeapMonth = false
        
        // 如果是春节前
        if remainingDays < 0 {
            // 返回上一年腊月
            let daysBeforeSpring = abs(remainingDays)
            if daysBeforeSpring <= 30 {
                return (month: 12, day: 30 - daysBeforeSpring + 1, isLeapMonth: false)
            } else {
                return (month: 11, day: 30, isLeapMonth: false)
            }
        }
        
        // 春节当天是正月初一
        if remainingDays == 0 {
            return (month: 1, day: 1, isLeapMonth: false)
        }
        
        // 遍历月份，使用2025年实际数据
        let monthData = monthDays2025
        for monthIndex in 0..<monthData.count {
            let daysInMonth = monthData[monthIndex]
            
            if remainingDays <= daysInMonth {
                return (month: currentMonth, day: remainingDays, isLeapMonth: false)
            }
            
            remainingDays -= daysInMonth
            
            // 在六月后插入闰六月
            if isLeapYear && currentMonth == leapMonth && !hasPassedLeapMonth {
                hasPassedLeapMonth = true
                
                if remainingDays <= leapMonthDays {
                    return (month: leapMonth, day: remainingDays, isLeapMonth: true)
                }
                remainingDays -= leapMonthDays
            }
            
            currentMonth += 1
        }
        
        // 超出当年，返回下一年正月
        return (month: 1, day: min(max(remainingDays, 1), 30), isLeapMonth: false)
    }
    
    /// 计算某年某日是第几天
    private static func getDayOfYear(year: Int, month: Int, day: Int) -> Int {
        let daysInMonth = [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
        var dayOfYear = day
        for i in 0..<(month - 1) {
            dayOfYear += daysInMonth[i]
        }
        return dayOfYear
    }
    
    /// 判断是否为闰年
    private static func isLeapYear(_ year: Int) -> Bool {
        return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
    }
    
    /// 获取中国传统节日（基于农历）
    static func chineseFestival(for date: Date) -> String? {
        let calendar = Calendar.current
        let components = calendar.dateComponents([.year, .month, .day], from: date)
        
        guard let year = components.year,
              let month = components.month,
              let day = components.day else {
            return nil
        }
        
        // 获取农历信息
        let lunarInfo = calculateLunarInfo(year: year, month: month, day: day)
        
        // 基于农历的传统节日
        switch (lunarInfo.month, lunarInfo.day, lunarInfo.isLeapMonth) {
        case (1, 1, false): return "春节"
        case (1, 15, false): return "元宵节"
        case (2, 2, false): return "龙抬头" 
        case (3, 3, false): return "上巳节"
        case (5, 5, false): return "端午节"
        case (7, 7, false): return "七夕节"
        case (7, 15, false): return "中元节"
        case (8, 15, false): return "中秋节"
        case (9, 9, false): return "重阳节"
        case (12, 8, false): return "腊八节"
        case (12, 23, false): return "小年"
        case (12, 30, false): return "除夕"
        case (12, 29, false): 
            // 如果农历腊月只有29天，则29日为除夕
            return "除夕"
        // 闰月相关节日（较少）
        case (6, 19, true): return "观世音菩萨成道日"
        default: break
        }
        
        // 基于公历的中国节日（清明等）
        switch (month, day) {
        case (4, 4): return "清明节"
        case (4, 5): return "清明节"
        default: return nil
        }
    }
    
    /// 获取二十四节气
    static func solarTerm(for date: Date) -> String? {
        let calendar = Calendar.current
        let components = calendar.dateComponents([.month, .day], from: date)
        let month = components.month ?? 0
        let day = components.day ?? 0
        
        // 2025年二十四节气准确日期
        let solarTerms2025: [Int: [Int: String]] = [
            1: [5: "小寒", 20: "大寒"],
            2: [3: "立春", 18: "雨水"],
            3: [5: "惊蛰", 20: "春分"],
            4: [4: "清明", 19: "谷雨"],
            5: [5: "立夏", 20: "小满"],
            6: [5: "芒种", 21: "夏至"],
            7: [6: "小暑", 22: "大暑"],
            8: [7: "立秋", 22: "处暑"],
            9: [7: "白露", 22: "秋分"],
            10: [8: "寒露", 23: "霜降"],
            11: [7: "立冬", 22: "小雪"],
            12: [6: "大雪", 21: "冬至"]
        ]
        
        if let termsInMonth = solarTerms2025[month],
           let term = termsInMonth[day] {
            return term
        }
        
        return nil
    }
    
    /// 获取国际节日
    static func internationalFestival(for date: Date) -> String? {
        let calendar = Calendar.current
        let components = calendar.dateComponents([.month, .day], from: date)
        let month = components.month ?? 0
        let day = components.day ?? 0
        
        switch (month, day) {
        case (1, 1): return "元旦"
        case (2, 14): return "情人节"
        case (3, 8): return "妇女节"
        case (4, 1): return "愚人节"
        case (5, 1): return "劳动节"
        case (5, 4): return "青年节"
        case (6, 1): return "儿童节"
        case (7, 1): return "建党节"
        case (8, 1): return "建军节"
        case (9, 10): return "教师节"
        case (10, 1): return "国庆节"
        case (12, 25): return "圣诞节"
        default: return nil
        }
    }
    
    /// 检查是否为中国法定节假日（放假日）
    static func isChineseHoliday(for date: Date) -> Bool {
        let calendar = Calendar.current
        let components = calendar.dateComponents([.year, .month, .day], from: date)
        let month = components.month ?? 0
        let day = components.day ?? 0
        let year = components.year ?? 2025
        
        // 2025年中国法定节假日安排
        switch (month, day) {
        // 元旦假期 (1月1日)
        case (1, 1): return true
            
        // 春节假期 (1月28日-2月4日, 2025年)
        case (1, 28), (1, 29), (1, 30), (1, 31): return year == 2025
        case (2, 1), (2, 2), (2, 3), (2, 4): return year == 2025
            
        // 清明节假期 (4月4日-4月6日)
        case (4, 4), (4, 5), (4, 6): return true
            
        // 劳动节假期 (5月1日-5月5日)
        case (5, 1), (5, 2), (5, 3), (5, 4), (5, 5): return true
            
        // 端午节假期 (5月31日-6月2日, 2025年)
        case (5, 31): return year == 2025
        case (6, 1), (6, 2): return year == 2025
            
        // 中秋节假期 (10月6日-10月8日, 2025年)
        case (10, 6), (10, 7), (10, 8): return year == 2025
            
        // 国庆节假期 (10月1日-10月7日)
        case (10, 1), (10, 2), (10, 3), (10, 4), (10, 5), (10, 6), (10, 7): return year == 2025
            
        default: return false
        }
    }
    
    /// 获取节假日标记（休/班）
    static func getHolidayMark(for date: Date) -> String? {
        if isChineseHoliday(for: date) {
            return "休"
        }
        
        // 可以添加调班日期标记
        let calendar = Calendar.current
        let components = calendar.dateComponents([.year, .month, .day], from: date)
        let month = components.month ?? 0
        let day = components.day ?? 0
        let year = components.year ?? 2025
        
        // 2025年调班日期
        if year == 2025 {
            switch (month, day) {
            // 春节调班：1月26日(周日)上班
            case (1, 26): return "班"
            // 五一调班：4月27日(周日)上班
            case (4, 27): return "班"
            // 国庆调班：9月28日(周日)、10月11日(周六)上班
            case (9, 28), (10, 11): return "班"
            default: break
            }
        }
        
        return nil
    }
    
    /// 获取所有节日和节气信息
    static func allInfo(for date: Date) -> [String] {
        var info: [String] = []
        
        if let solarTerm = solarTerm(for: date) {
            info.append(solarTerm)
        }
        
        if let chineseFestival = chineseFestival(for: date) {
            info.append(chineseFestival)
        }
        
        if let internationalFestival = internationalFestival(for: date) {
            info.append(internationalFestival)
        }
        
        // 如果没有特殊节日，则显示农历
        if info.isEmpty {
            info.append(lunarDate(for: date))
        }
        
        return info
    }
}